#pragma once

#include <vector>
#include <cassert>

namespace jiuqilog
{
#define DEFAULT_BUFFER_SIZE (10 * 1024 * 1024)
#define THRESHOLD_BUFFER_SIZE (80 * 1024 * 1024)
#define INCREMENT_BUFFER_SIZE (10 * 1024 * 1024)
    class Buffer
    {
    public:
        Buffer() : _buffer(DEFAULT_BUFFER_SIZE),
                   _read_pos(0), _write_pos(0)
        {
        }

        // 写入数据
        void push(const char *data, size_t len)
        {
            // 空间不够则扩容
            ensureEnoughSize(len);
            // 将数据拷贝到缓冲区
            std::copy(data, data + len, &_buffer[_write_pos]);
            // 可写指针后移
            moveWrite(len);
        }

        // 可写空间大小:如果采取无限扩容策略,则这个接口没用
        size_t writeAbleSize() { return _buffer.size() - _write_pos; }
        // 获取可读数据的起始地址
        const char *begin()  { return &_buffer[_read_pos]; }
        // 获取可读数据的长度
        size_t readAbleSize() { return _write_pos - _read_pos; }

        void moveRead(size_t len)
        {
            assert(len <= readAbleSize());
            _read_pos += len;
        }
        // 交换缓冲区
        void swap(Buffer &buffer)
        {
            _buffer.swap(buffer._buffer);
            std::swap(_read_pos, buffer._read_pos);
            std::swap(_write_pos, buffer._write_pos);
        }
        // 初始化缓冲区
        void reset()
        {
            _read_pos = 0;
            _write_pos = 0;
        }
        // 判断缓冲区是否为空
        bool empty() { return _write_pos == _read_pos; }

    private:
        // 对空间进行扩容
        void ensureEnoughSize(size_t len)
        {
            if (len <= writeAbleSize())
                return;
            // 设定一个阈值,达到阈值前采取近似二倍扩容,达到后采取线性扩容
            size_t new_size = 0;
            if (_buffer.size() < THRESHOLD_BUFFER_SIZE)
                new_size = _buffer.size() * 2 + len;
            else
                new_size = _buffer.size() + INCREMENT_BUFFER_SIZE + len;
            _buffer.resize(new_size);
        }

        void moveWrite(size_t len)
        {
            assert(len <= writeAbleSize());
            _write_pos += len;
        }

    private:
        std::vector<char> _buffer;
        size_t _read_pos;  // 可读数据的指针
        size_t _write_pos; // 可写位置的指针
    };
}